﻿/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库。
 * CopyRight (C) 2012-2022 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI.git
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI can be used for free under the GPL-3.0 license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: USevenZip.cs
 * 文件说明: 7z帮助类
 * 当前版本: V3.1
 * 创建日期: 2020-01-01
 *
 * 2020-01-01: V2.2 增加文件说明
******************************************************************************/

using SevenZip;
using System;
using System.IO;

namespace Sunny.UI
{
    /// <summary>
    /// 7-zip Helper（不需要 7z.exe 和 7z.dll）
    /// </summary>
    public static class SevenZipEx
    {
        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="inStream"></param>
        /// <param name="outStream"></param>
        public static void Zip(Stream inStream, Stream outStream)
        {
            int dictionary = 1 << 23;
            int posStateBits = 2;
            int litContextBits = 3; // for normal files
            int litPosBits = 0;
            int algorithm = 2;
            int numFastBytes = 128;
            string mf = "bt4";
            const bool eos = false;

            CoderPropID[] propIDs =
                {
                    CoderPropID.DictionarySize,
                    CoderPropID.PosStateBits,
                    CoderPropID.LitContextBits,
                    CoderPropID.LitPosBits,
                    CoderPropID.Algorithm,
                    CoderPropID.NumFastBytes,
                    CoderPropID.MatchFinder,
                    CoderPropID.EndMarker
                };

            object[] properties =
                {
                    dictionary,
                    posStateBits,
                    litContextBits,
                    litPosBits,
                    algorithm,
                    numFastBytes,
                    mf,
                    eos
                };

            SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
            encoder.SetCoderProperties(propIDs, properties);
            encoder.WriteCoderProperties(outStream);
            long fileSize = inStream.Length;
            for (int i = 0; i < 8; i++)
            {
                outStream.WriteByte((byte)(fileSize >> (8 * i)));
            }

            encoder.Code(inStream, outStream, -1, -1, null);
        }

        /// <summary>
        /// 解压缩
        /// </summary>
        /// <param name="inStream"></param>
        /// <param name="outStream"></param>
        public static void Unzip(Stream inStream, Stream outStream)
        {
            byte[] properties = new byte[5];
            if (inStream.Read(properties, 0, 5) != 5)
            {
                throw (new Exception("input .lzma is too short"));
            }

            SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
            decoder.SetDecoderProperties(properties);

            long outSize = 0;
            for (int i = 0; i < 8; i++)
            {
                int v = inStream.ReadByte();
                if (v < 0)
                {
                    throw (new Exception("Can't Read 1"));
                }

                outSize |= ((long)(byte)v) << (8 * i);
            }

            long compressedSize = inStream.Length - inStream.Position;
            decoder.Code(inStream, outStream, compressedSize, outSize, null);
        }

        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="OriPath">原文件地址</param>
        /// <param name="destPath">目标文件</param>
        public static void Zip(string OriPath, string destPath)
        {
            FileStream inStream = new FileStream(OriPath, FileMode.Open);
            FileStream outStream = new FileStream(destPath, FileMode.Create);
            Zip(inStream, outStream);

            //关闭文件流
            inStream.Close();
            outStream.Close();
        }

        /// <summary>
        /// 解压
        /// </summary>
        /// <param name="OriPath">原文件地址</param>
        /// <param name="destPath">目标文件</param>
        public static void Unzip(string OriPath, string destPath)
        {
            FileStream inStream = new FileStream(OriPath, FileMode.Open);
            FileStream outStream = new FileStream(destPath, FileMode.Create);

            Unzip(inStream, outStream);

            //关闭文件流
            inStream.Close();
            outStream.Close();
        }

        /// <summary>
        /// 压缩数组
        /// </summary>
        /// <param name="bytes">数组</param>
        /// <returns>数组</returns>
        public static byte[] Zip(byte[] bytes)
        {
            MemoryStream inStream = new MemoryStream(bytes);
            MemoryStream outStream = new MemoryStream();

            Zip(inStream, outStream);

            byte[] result = outStream.ToArray();

            //关闭文件流
            inStream.Close();
            outStream.Close();

            return result;
        }

        /// <summary>
        /// 解压缩数组
        /// </summary>
        /// <param name="bytes">数组</param>
        /// <returns>数组</returns>
        public static byte[] Unzip(byte[] bytes)
        {
            MemoryStream inStream = new MemoryStream(bytes);
            MemoryStream outStream = new MemoryStream();

            Unzip(inStream, outStream);
            byte[] result = outStream.ToArray();

            //关闭文件流
            inStream.Close();
            outStream.Close();
            return result;
        }
    }
}